KM 4: Add Root-of-Trust test cases This patch is a squash of following patches: - aosp/2582033 - aosp/2603248 Bug: 255344624 Test: VtsHalKeymasterV4_0TargetTest Change-Id: I46e62ab9031d3745f99bd214f9e579e80edc9128 Merged-In: I46e62ab9031d3745f99bd214f9e579e80edc9128
diff --git a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h index cc71dd1..ad018e2 100644 --- a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h +++ b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
@@ -17,6 +17,11 @@ #ifndef HARDWARE_INTERFACES_KEYMASTER_4_0_SUPPORT_OPENSSL_UTILS_H_ #define HARDWARE_INTERFACES_KEYMASTER_4_0_SUPPORT_OPENSSL_UTILS_H_ +#include <openssl/bn.h> +#include <openssl/evp.h> +#include <openssl/rsa.h> +#include <openssl/x509.h> + #include <android/hardware/keymaster/4.0/types.h> template <typename T, void (*F)(T*)>
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp index 333e408..e7dc37e 100644 --- a/keymaster/4.0/vts/functional/Android.bp +++ b/keymaster/4.0/vts/functional/Android.bp
@@ -18,6 +18,7 @@ name: "VtsHalKeymasterV4_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ + "BootloaderStateTest.cpp", "HmacKeySharingTest.cpp", "KeymasterHidlTest.cpp", "VerificationTokenTest.cpp", @@ -25,7 +26,10 @@ ], static_libs: [ "android.hardware.keymaster@4.0", + "libavb_user", + "libavb", "libcrypto", + "libfs_mgr", "libkeymaster4support", "libsoftkeymasterdevice", ],
diff --git a/keymaster/4.0/vts/functional/BootloaderStateTest.cpp b/keymaster/4.0/vts/functional/BootloaderStateTest.cpp new file mode 100644 index 0000000..fd9ccc7 --- /dev/null +++ b/keymaster/4.0/vts/functional/BootloaderStateTest.cpp
@@ -0,0 +1,141 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <memory> +#include <optional> +#include <string> +#include <vector> + +#include <android-base/properties.h> +#include <fstab/fstab.h> +#include <libavb/libavb.h> +#include <libavb_user/avb_ops_user.h> + +#include "KeymasterHidlTest.h" + +namespace android::hardware::keymaster::V4_0::test { + +using ::std::string; +using ::std::vector; + +// Since this test needs to talk to Keymaster HAL, it can only run as root. Thus, +// bootloader can not be locked. +// @CddTest = 9.10/C-0-2 +class BootloaderStateTest : public KeymasterHidlTest { + public: + virtual void SetUp() override { + KeymasterHidlTest::SetUp(); + + // Generate a key. + auto ec = GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(EcCurve::P_256) + .Digest(Digest::SHA_2_256)); + ASSERT_EQ(ec, ErrorCode::OK) << "Failed to generate key."; + + // Generate attestation. + hidl_vec<hidl_vec<uint8_t>> cert_chain; + ec = AttestKey(AuthorizationSetBuilder() + .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge")) + .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")), + &cert_chain); + ASSERT_EQ(ec, ErrorCode::OK) << "Failed to generate attestation."; + + X509_Ptr cert(parse_cert_blob(cert_chain[0])); + ASSERT_TRUE(cert.get()) << "Failed to parse certificate blob."; + + ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get()); + ASSERT_TRUE(attest_rec) << "Failed to get attestation record."; + + // Parse root of trust. + auto result = parse_root_of_trust(attest_rec->data, attest_rec->length, &attestedVbKey_, + &attestedVbState_, &attestedBootloaderState_, + &attestedVbmetaDigest_); + ASSERT_EQ(result, ErrorCode::OK) << "Failed to parse root of trust."; + } + + hidl_vec<uint8_t> attestedVbKey_; + keymaster_verified_boot_t attestedVbState_; + bool attestedBootloaderState_; + hidl_vec<uint8_t> attestedVbmetaDigest_; +}; + +// Check that attested bootloader state is set to unlocked. +TEST_F(BootloaderStateTest, BootloaderIsUnlocked) { + ASSERT_FALSE(attestedBootloaderState_) + << "This test runs as root. Bootloader must be unlocked."; +} + +// Check that verified boot state is set to "unverified", i.e. "orange". +TEST_F(BootloaderStateTest, VbStateIsUnverified) { + // Unlocked bootloader implies that verified boot state must be "unverified". + ASSERT_EQ(attestedVbState_, KM_VERIFIED_BOOT_UNVERIFIED) + << "Verified boot state must be \"UNVERIFIED\" aka \"orange\"."; + + // AVB spec stipulates that bootloader must set "androidboot.verifiedbootstate" parameter + // on the kernel command-line. This parameter is exposed to userspace as + // "ro.boot.verifiedbootstate" property. + auto vbStateProp = ::android::base::GetProperty("ro.boot.verifiedbootstate", ""); + ASSERT_EQ(vbStateProp, "orange") + << "Verified boot state must be \"UNVERIFIED\" aka \"orange\"."; +} + +// Following error codes from avb_slot_data() mean that slot data was loaded +// (even if verification failed). +static inline bool avb_slot_data_loaded(AvbSlotVerifyResult result) { + switch (result) { + case AVB_SLOT_VERIFY_RESULT_OK: + case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: + case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: + case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: + return true; + default: + return false; + } +} + +// Check that attested vbmeta digest is correct. +TEST_F(BootloaderStateTest, VbmetaDigest) { + AvbSlotVerifyData* avbSlotData; + auto suffix = fs_mgr_get_slot_suffix(); + const char* partitions[] = {nullptr}; + auto avbOps = avb_ops_user_new(); + + // For VTS, devices run with vendor_boot-debug.img, which is not release key + // signed. Use AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR to bypass avb + // verification errors. This is OK since we only care about the digest for + // this test case. + auto result = avb_slot_verify(avbOps, partitions, suffix.c_str(), + AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR, + AVB_HASHTREE_ERROR_MODE_EIO, &avbSlotData); + ASSERT_TRUE(avb_slot_data_loaded(result)) << "Failed to load avb slot data"; + + // Unfortunately, bootloader is not required to report the algorithm used + // to calculate the digest. There are only two supported options though, + // SHA256 and SHA512. Attested VBMeta digest must match one of these. + vector<uint8_t> digest256(AVB_SHA256_DIGEST_SIZE); + vector<uint8_t> digest512(AVB_SHA512_DIGEST_SIZE); + + avb_slot_verify_data_calculate_vbmeta_digest(avbSlotData, AVB_DIGEST_TYPE_SHA256, + digest256.data()); + avb_slot_verify_data_calculate_vbmeta_digest(avbSlotData, AVB_DIGEST_TYPE_SHA512, + digest512.data()); + + ASSERT_TRUE((attestedVbmetaDigest_ == digest256) || (attestedVbmetaDigest_ == digest512)) + << "Attested digest does not match computed digest."; +} + +} // namespace android::hardware::keymaster::V4_0::test
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp index 3af1df3..ef798f2 100644 --- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp +++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -752,6 +752,30 @@ return {}; } +X509* parse_cert_blob(const hidl_vec<uint8_t>& blob) { + const uint8_t* p = blob.data(); + return d2i_X509(nullptr, &p, blob.size()); +} + +ASN1_OCTET_STRING* get_attestation_record(X509* certificate) { + ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */)); + EXPECT_TRUE(!!oid.get()); + if (!oid.get()) return nullptr; + + int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */); + EXPECT_NE(-1, location) << "Attestation extension not found in certificate"; + if (location == -1) return nullptr; + + X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location); + EXPECT_TRUE(!!attest_rec_ext) + << "Found attestation extension but couldn't retrieve it? Probably a BoringSSL bug."; + if (!attest_rec_ext) return nullptr; + + ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext); + EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data"; + return attest_rec; +} + } // namespace test } // namespace V4_0 } // namespace keymaster
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h index 015fc43..372f1e1 100644 --- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h +++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -24,7 +24,9 @@ #include <keymaster/keymaster_configuration.h> +#include <keymasterV4_0/attestation_record.h> #include <keymasterV4_0/authorization_set.h> +#include <keymasterV4_0/openssl_utils.h> namespace android { namespace hardware { @@ -237,6 +239,11 @@ static hidl_string author_; }; +X509* parse_cert_blob(const hidl_vec<uint8_t>& blob); +// Extract attestation record from cert. Returned object is still part of cert; don't free it +// separately. +ASN1_OCTET_STRING* get_attestation_record(X509* certificate); + } // namespace test } // namespace V4_0 } // namespace keymaster
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp index f95f658..01caa58 100644 --- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp +++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -194,11 +194,6 @@ void operator()(RSA* p) { RSA_free(p); } }; -X509* parse_cert_blob(const hidl_vec<uint8_t>& blob) { - const uint8_t* p = blob.data(); - return d2i_X509(nullptr, &p, blob.size()); -} - bool verify_chain(const hidl_vec<hidl_vec<uint8_t>>& chain, const std::string& msg, const std::string& signature) { { @@ -268,27 +263,6 @@ return true; } -// Extract attestation record from cert. Returned object is still part of cert; don't free it -// separately. -ASN1_OCTET_STRING* get_attestation_record(X509* certificate) { - ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */)); - EXPECT_TRUE(!!oid.get()); - if (!oid.get()) return nullptr; - - int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */); - EXPECT_NE(-1, location) << "Attestation extension not found in certificate"; - if (location == -1) return nullptr; - - X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location); - EXPECT_TRUE(!!attest_rec_ext) - << "Found attestation extension but couldn't retrieve it? Probably a BoringSSL bug."; - if (!attest_rec_ext) return nullptr; - - ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext); - EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data"; - return attest_rec; -} - bool tag_in_list(const KeyParameter& entry) { // Attestations don't contain everything in key authorization lists, so we need to filter // the key lists to produce the lists that we expect to match the attestations.